import { NextResponse, type NextRequest } from 'next/server';
import corsMiddleware from './middlewares/cors';
import authMiddleware from './middlewares/auth';
import nextMiddleware from './middlewares/next';
import redirectMiddleware from './middlewares/redirect';
import rewriteMiddleware from './middlewares/rewrite';
import fallbackMiddleware from './middlewares/fallback';
import maintainMiddleware from './middlewares/maintain';

type NextFn<T> = (v: T) => any;
type MW<T> = (v: T, n: NextFn<T>) => any;
function composeMiddlewares<T>(...middlewares: MW<T>[]) {
  const middle = middlewares.reduceRight(
    (nextFn, mw) => {
      const next: NextFn<T> = nextFn as NextFn<T>;
      return async (value: T) => {
        return await mw(value, next);
      };
    },
    (value: T) => value
  );

  const handler: NextFn<T> = middle as NextFn<T>;
  return handler;
}

export async function middleware(request: NextRequest, ...args: any[]) {
  // middlewares order is important!
  const handler = composeMiddlewares(
    maintainMiddleware, // enable maintaining mode
    authMiddleware,
    corsMiddleware,
    nextMiddleware,
    redirectMiddleware,
    rewriteMiddleware,
    fallbackMiddleware
  );
  return handler(request);
}

export const config = {
  matcher: ['/:path*'],
};
